#include "unit.h"
using namespace Units;
//===============================================
// unit++++++++++++++++++++++++++++++++++++++++++
// a "fleet" of subunits.  has a position, a parent
// and a number assosiated with each type
//-----------------------------------------------
Units::unit::unit(){
    facing = up;
    amdead = false;
    powerstat = powerbuff = 0;
    speedstat = speedbuff = 0;
    cohesionstat = cohesionbuff = 0;
    ap = 0;
    posx = -1;
    posy = -1;
    lib = unitLib::staticLib();
    lib->record(this);
    parent = NULL;
}
Units::unit::unit(unitLib* _lib){
    facing = up;
    powerstat = powerbuff = 0;
    speedstat = speedbuff = 0;
    cohesionstat = cohesionbuff = 0;
    ap = 0;
    posx = -1;
    posy = -1;
    lib = _lib;
    lib->record(this);
    parent = NULL;
}
Units::unit::unit(unit* u){
    amdead = false;
    powerstat = powerbuff = 0;
    speedstat = speedbuff = 0;
    cohesionstat = cohesionbuff = 0;
    ap = 0;
    posx = -1;
    posy = -1;
    lib = unitLib::staticLib();
    lib->record(this);
    facing = u->facing;
    parent = NULL;
}
Units::unit::~unit(){
    if(parent != NULL) parent->remUnit(this);
    lib->killUnit(this);
}
void Units::unit::record(unitLib* rec){
    if(lib != NULL){
        lib->removeUnit(this, posx, posy);
        lib->killUnit(this);
    }
    lib = rec;
    lib->record(this);
}
void Units::unit::add(subunit* su, int num){
    subunitList[su] += num;
}
void Units::unit::remove(subunit* su, int num){
    if(subunitList.find(su) != subunitList.end()){
        subunitList[su] -= num;
        if(subunitList[su] <= 0){
            subunitList.erase(su);
        }
    }
}
void Units::unit::recieve(unit* u){
    map<subunit*, int>::iterator sui = (u)->unititer();
    for(int i = 0; i < (u)->sunits(); i++, sui++){
        add(sui->first, sui->second);
        (u)->remove(sui->first,  sui->second);
    }
    Units::unitLib::staticLib()->killUnit(u);
}
void Units::unit::setParent(unitgroup* gp){
    if(parent != NULL){
        parent->remUnit(this);
    }
    parent = gp;
}
Units::unitgroup* Units::unit::getParent(){
    return parent;
}
int Units::unit::apoints(){
    return ap;
}
bool Units::unit::useap(int _ap){
    if(ap - _ap >= 0){
        ap -= _ap;
        return true;
    }
    return false;
}
void Units::unit::resetAP(){
    if(subunitList.empty()){
        ap = 0;
    }
    //vars
    map<subunit*, int>::iterator iter;
    //reset ap
    ap = subunitList.begin()->first->spd();
    //find max
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        if(iter->second > 0 && iter->first->spd() < ap){
            ap = iter->first->spd();
        }
    }
}
Units::direction Units::unit::relation(int x, int y){
    y -= posy;
    x -= posx;
    if(y < 0 && x <= -1 * y && x >= y){
       return up;
    }
    if(y > 0 && x >= -1 * y && x <= y){
        return down;
    }
    if(x < 0  && y < -1 * x && y > x){
        return left;
    }
    if(x > 0  && y > -1 * x && y < x){
        return right;
    }
    return up;
}
bool Units::unit::dead(){
    if(amdead){
        return amdead;
    }
    map<subunit*, int>::iterator iter;
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        if(iter->second > 0){
            return false;
        }
    }
    amdead = true;
    return true;
}
int Units::unit::nums(subunit* su){
    if(subunitList.find(su) != subunitList.end())
        return subunitList[su];
    return 0;
}
int Units::unit::power(int buff){
    powerbuff += buff;
    return powerstat + powerbuff;
}
int Units::unit::speed(int buff){
    speedbuff += buff;
    return speedstat + speedbuff;
}
int Units::unit::cohesion(int buff){
    cohesionbuff += buff;
    return cohesionstat + cohesionbuff;
}
bool Units::unit::move(int mx, int my){
    int dist = sqrt((posx - mx) * (posx - mx) + (posy - my) * (posy -  my));
    if(!useap(dist)){
        return false;
    }
    return place(mx, my);
}
bool Units::unit::place(int mx, int my){
    if(lib != NULL && !lib->move(this, posx, posy, mx, my)){
        return false;
    }
    posx = mx;
    posy = my;
    return true;
}
bool Units::unit::face(direction dir){
//    if(useap(1)){
        facing = dir;
        return true;
  //  }
    //return false;
}
Units::direction Units::unit::face(){
    return facing;
}
Units::formation Units::unit::gForm(){
    return form;
}
void Units::unit::sForm(formation f){
    form = f;
}
Units::voley* Units::unit::shoot(int mx, int my, bateryType tp){
    //varblock
    int acst = 0;
    voley* vol;
    map<subunit*, int>::iterator iter;
    //check for ap - return null if not enough
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        if(iter->second > 0 && iter->first->spd() > acst){
            acst = iter->first->gbattery(tp)->apCost();
        }
    }
    if(!useap(acst)){
        return NULL;
    }
    //fill the voley
    vol = new voley(posx, posy);
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        vol->pushBullet(iter->first->shoot(tp), iter->second);
    }
    //buff and return
    vol->buff(damBuff, accBuff);
    return vol;
}
bool Units::unit::useShield(int x, int y){
    return facing == relation(x,y);
}
void Units::unit::takeDamage(voley* vol){
    //param check
    if(vol == NULL){
        return;
    }
    //varblok
    bool ushd = useShield(vol->getX(), vol->getY());
    int num;
    int total = 0;
    int size = vol->size();
    map<subunit*, int>::iterator iter;
    //assign buffs
    vol->buff((-1 * shdBuff), (-1 * evaBuff));
    vol->print();
    //find total
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        total += iter->second;
    }
    //do the damage
    for(iter = subunitList.begin(); iter != subunitList.end(); iter++){
        num = size * (double(iter->second)/total);
        iter->second -= iter->first->dead(num, vol, ushd);
        if(iter->second <= 0){
            iter->second = 0;
        }
    }
    if(dead()){
        lib->killUnit(this);
    }

}
//===============================================